#include "iomanager.h"

namespace sylar
{

    IOManager *IOManager::GetThis()
    {
        // 返回当前线程的IOManager指针(如果没有就nullptr)
        return dynamic_cast<IOManager *>(Sheduler::getthis());
    }

    IOManager::FdContext::EventContext &IOManager::FdContext::getEventContext(Event event)
    {
        // 根据事件获取事件上下文
        assert(event == WRTIE || event == READ);
        switch (event)
        {
        case READ:
            /* code */
            return readContext;
            break;

        case WRTIE:
            return writeContext;
            break;
        default:
            throw std::invalid_argument("getEventContext: invalid Event type");
        }
    }
    void IOManager::FdContext::resetEventContext(EventContext &evc)
    {
        evc._fiber.reset();
        evc._func = nullptr;
        evc._sheduler = nullptr;
    }
    void IOManager::FdContext::triggerEvent(Event event)
    {
        //std::cout<<"触发成功"<<std::endl;
        assert(_events & event);                          // event必须是_events中的事件
        _events = static_cast<Event>(_events & (~event)); // 从_events事件中剔除event事件

        EventContext& ctx = getEventContext(event); // 读上下文或者写上下文
        // 将fd的协程或者函数任务push到期归属的_sheduler中，后续线程抢单执行
        if (ctx._fiber)
        {
            ctx._sheduler->push(ctx._fiber);
        }
        else
        {
            ctx._sheduler->push(ctx._func);
            //std::cout<<"push成功函数"<<std::endl;
        }
        resetEventContext(ctx); // 将已经push到任务的上下文信息置为空
    }

    void IOManager::contextResize(size_t size)
    {
        _FdContextV.resize(size);
        // 初始化，vector的下标对应fd
        for (int i = 0; i < size; i++)
        {
            if (_FdContextV[i] == nullptr)
            {
                _FdContextV[i] = new FdContext();
                _FdContextV[i]->_sockfd = i;
            }
        }
    }

    IOManager::IOManager(size_t threads, bool use_caller, const std::string &name)
        : Sheduler(threads, use_caller, name), TimerManager()
    {
        // 创建epoll模型和pipe管道，启动调度器
        int epollfd = epoll_create(1111);
        _epoll_fd = epollfd;
        assert(epollfd > 0);
        // 0是嘴巴读段 1是笔写端
        int ret = pipe(_tickleFds);
        assert(ret != -1);
        // 创建事件模型边缘触发监听读端，因此要将其设置为ONOBLOCK
        epoll_event events;
        events.data.fd = _tickleFds[0];
        events.events = EPOLLIN | EPOLLET;
        ret = fcntl(_tickleFds[0], F_SETFL, O_NONBLOCK);
        assert(ret != -1);
        ret = epoll_ctl(epollfd, EPOLL_CTL_ADD, _tickleFds[0], &events);
        assert(ret != -1);
        contextResize(50);
        start(); // 启动sheduler的线程池
    }
    IOManager::~IOManager()
    {
        stop();
        close(_epoll_fd);
        close(_tickleFds[0]);
        close(_tickleFds[1]);
        for (int i = 0; i < _FdContextV.size(); i++)
        {
            if (_FdContextV[i])
            {
                delete _FdContextV[i];
            }
        }
    }
    int IOManager::addEvent(int fd, Event event, std::function<void()> func)
    {
        // 首先先判断fd在不在fdcontextv中，不在则扩容
        FdContext *fdctx = nullptr;
        std::shared_lock<std::shared_mutex> read_lock(_smtx);
        if (fd < _FdContextV.size())
        {
            fdctx = _FdContextV[fd];
            read_lock.unlock();
        }
        else
        {
            read_lock.unlock();
            std::unique_lock<std::shared_mutex> write_lock(_smtx);
            contextResize(fd * 1.5);
            fdctx = _FdContextV[fd];
        }
        std::unique_lock<std::mutex> lock(fdctx->_mtx);
        // 检测添加的事件是否已经存在
        if (event & fdctx->_events)
        {
            return -1;
        }
        // 添加事件到epoll树中
        int op = fdctx->_events ? EPOLL_CTL_MOD : EPOLL_CTL_ADD;
        epoll_event epollenvent;
        epollenvent.events = fdctx->_events | event | EPOLLET;
        epollenvent.data.ptr = fdctx;
        int ret = epoll_ctl(_epoll_fd, op, fd, &epollenvent);
        if (ret == -1)
        {
            logmessage(ERROR, "添加事件失败");
            return -1;
        }
        ++_pendingEventCount;
        // 更新events
        fdctx->_events = (Event)(fdctx->_events | event);
        // 设置事件上下文

        FdContext::EventContext &ectx = fdctx->getEventContext(event);
        ectx._sheduler = Sheduler::getthis();
        if (func)
        {
            ectx._func.swap(func);
        }
        else
        {
            ectx._fiber = Fiber::getthis();
        }
        return 0;
    }

    bool IOManager::delEvent(int fd, Event event)
    {
        FdContext *fdctx = nullptr;
        std::shared_lock<std::shared_mutex> read_lock(_smtx);
        // 查找fd是否已存在
        if (_FdContextV.size() > fd)
        {
            // 存在此fd
            fdctx = _FdContextV[fd];
            read_lock.unlock();
        }
        else
        {
            read_lock.unlock();
            return false;
        }

        std::unique_lock<std::mutex> write_lock(fdctx->_mtx);
        // 查找要删除的事件是否在上下文events中
        if (!(fdctx->_events & event))
        {
            return false;
        }
        // 删除events中的event的事件
        Event new_events = (Event)(fdctx->_events & ~event);
        int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
        epoll_event evt;
        evt.events = new_events | EPOLLET;
        evt.data.ptr = fdctx; // epoll关联到上下文

        int ret = epoll_ctl(_epoll_fd, op, fd, &evt);

        if (ret == -1)
        {
            logmessage(ERROR, "在epoll_ctl删除事件失败");
            return false;
        }
        // 更新fdctx信息
        fdctx->_events = new_events;
        --_pendingEventCount;

        // 重置事件的处理上下文信息
        IOManager::FdContext::EventContext &ectx = fdctx->getEventContext(event);
        fdctx->resetEventContext(ectx);
        return true;
    }

    bool IOManager::cancelEvent(int fd, Event event)
    {
        FdContext *fdctx = nullptr;
        std::shared_lock<std::shared_mutex> read_lock(_smtx);
        // 查找fd是否已存在
        if (_FdContextV.size() > fd)
        {
            // 存在此fd
            fdctx = _FdContextV[fd];
            read_lock.unlock();
        }
        else
        {
            read_lock.unlock();
            return false;
        }

        std::unique_lock<std::mutex> write_lock(fdctx->_mtx);
        // 查找要删除的事件是否在上下文events中
        if (!(fdctx->_events & event))
        {
            return false;
        }
        // 删除events中的event的事件
        Event new_events = (Event)(fdctx->_events & ~event);
        int op = new_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
        epoll_event evt;
        evt.events = new_events | EPOLLET;
        evt.data.ptr = fdctx; // epoll关联到上下文

        int ret = epoll_ctl(_epoll_fd, op, fd, &evt);

        if (ret == -1)
        {
            logmessage(ERROR, "在epoll_ctl删除事件失败");
            return false;
        }
        // 更新fdctx信息
        fdctx->_events = new_events;
        --_pendingEventCount;

        // 重置事件的处理上下文信息
        fdctx->triggerEvent(event);
        return true;
    }
    bool IOManager::cancelAll(int fd)
    {
        // 取消指定fd上的所有事件
        // 查找fd是否存在
        FdContext *fdctx = nullptr;
        std::shared_lock<std::shared_mutex> read_lock(_smtx);
        if (fd < _FdContextV.size())
        {
            fdctx = _FdContextV[fd];
            read_lock.unlock();
        }
        else
        {
            read_lock.unlock();
            return false;
        }
        // 开始处理fdctx上的事件
        std::unique_lock<std::mutex> lock(fdctx->_mtx);
        if (!fdctx->_events)
        {
            return false;
        }

        int ret = epoll_ctl(_epoll_fd, EPOLL_CTL_DEL, fd, nullptr);
        if (ret == -1)
        {
            logmessage(ERROR, "epoll_ctl epoll_ctl_del faild");
            return false;
        }

        if (fdctx->_events & READ)
        {
            fdctx->triggerEvent(READ);
            --_pendingEventCount;
        }
        if (fdctx->_events & WRTIE)
        {
            fdctx->triggerEvent(WRTIE);
            --_pendingEventCount;
        }
        return true;
    }
    void IOManager::tickle()
    {

        if (!hasidlthreads())
        {
            // 不存在空闲线程
            return;
        }
        int ret = write(_tickleFds[1], "T", 1);
        assert(ret == 1);
        return;
    }
    bool IOManager::can_stop()
    {
        uint64_t timeout = getNextTimer();
        return timeout == ~0ull && _pendingEventCount == 0 && Sheduler::can_stop();
    }

    void IOManager::idle() //处理epoll事件的核心逻辑
    {
        static const int MAXEVENTS = 52;
        std::unique_ptr<epoll_event[]> events(new epoll_event[MAXEVENTS]);
        while (!can_stop())
        {
            int ret = 0;
            while (true)
            {
                uint64_t nextimeout = getNextTimer();
                static const uint64_t MAXTIMEOUT = 5000;
                nextimeout = std::min(nextimeout, MAXTIMEOUT);
                ret = epoll_wait(_epoll_fd, events.get(), MAXEVENTS, (int)nextimeout);
                if (ret < 0 && errno == EINTR)
                {
                    continue;
                }
                else
                {
                    break;
                }
            }
            std::vector<func_t> cbs;
            getExpiredfunc(cbs);
            if (!cbs.empty())
            {
                for (const auto &x : cbs)
                {
                    push(x);
                }
                cbs.clear();
            }

            // 处理epollwait事件
            for (int i = 0; i < ret; i++)
            {
                epoll_event &event = events[i];
                if (event.data.fd == _tickleFds[0])
                {
                    uint8_t dummy[256];
                    while (read(event.data.fd, dummy, sizeof dummy) > 0)
                        ;
                    continue; // 起到唤醒作用
                }
                FdContext *fd_ctx = (FdContext *)event.data.ptr; // 通过 event.data.ptr 获取与当前事件关联的 FdContext 指针 fd_ctx，该指针包含了与文件描述符相关的上下文信息。
                std::lock_guard<std::mutex> lock(fd_ctx->_mtx);
                int real_events = NONE;
                if (event.events & EPOLLIN)
                {
                    real_events |= READ;
                }
                if (event.events & EPOLLOUT)
                {
                    real_events |= WRTIE;
                }

                if ((fd_ctx->_events & real_events) == NONE)
                {
                    continue;
                }

                // delete the events that have already happened
                // 这里进行取反就是计算剩余未发送的的事件
                int left_events = (fd_ctx->_events & ~real_events);

                int op = left_events ? EPOLL_CTL_MOD : EPOLL_CTL_DEL;
                event.events = EPOLLET | left_events; // 如果left_event没有事件了那么就只剩下边缘触发了events设置了

                // 根据之前计算的操作（op），调用 epoll_ctl 更新或删除 epoll 监听，如果失败，打印错误并继续处理下一个事件。
                int rt2 = epoll_ctl(_epoll_fd, op, fd_ctx->_sockfd, &event);
                if (rt2)
                {
                    std::cerr << "idle::epoll_ctl failed: " << strerror(errno) << std::endl;
                    continue;
                }
                if (real_events & READ)
                {
                    fd_ctx->triggerEvent(READ);
                    --_pendingEventCount;
                }
                if (real_events & WRTIE)
                {
                    fd_ctx->triggerEvent(WRTIE);
                    --_pendingEventCount;
                }
            }
            //当前线程的协程主动让出控制权，调度器可以选择执行其他任务或再次进入 idle 状态。
            Fiber::getthis()->yield();
        }
    }
    void IOManager::onTimerInsertAtFront(){
        tickle();
    }
};